import LineManager from "./classes/LineManager.js"
import StationManager from "./classes/StationManager.js"
import Path from './classes/Path.js'

/**
 * dijkstra核心方法类
 */
const Dijkstra = {
  lineManager: null,
  stationManager: null,
  stationList: [],
  stationIndexMap: null,
  pathMatrix: [],
  stationCount: 0,
  
  __init() {
    this.lineManager = new LineManager()
    this.stationManager = new StationManager()
    this.stationIndexMap = new Map()
  },
  __fillData(stationData) {
    if (!Array.isArray(stationData)) {
      throw "数据格式不正确"
    }
    stationData.forEach(lineData => {
      const lineName = lineData['name']
      const isRing = lineData['ring']
      const stationNameList = lineData['stations']
      
      if (!Array.isArray(stationNameList) || lineName === undefined || isRing === undefined) {
        throw "数据格式不正确"
      }
      
      stationNameList.forEach(stationName => {
        this.stationManager.addLine(stationName, lineName)
        this.lineManager.addStation(lineName, stationName, isRing)
      })
    })
    
    
    let index = 0
    this.stationManager.stationMap.forEach((station, stationName) => {
      this.stationIndexMap.set(stationName, index ++)
      this.stationList.push(station)
    })
    
    this.stationCount = this.stationList.length
  },
  __initPathMatrix() {
    for (let i = 0; i < this.stationCount; i ++) {
      this.pathMatrix.push([])
      for (let j = 0; j < this.stationCount; j ++) {
        const lineNameList = this.stationManager.getLineNameListWithSameFromToStation(this.stationList[i], this.stationList[j])
        this.pathMatrix[i].push(this.lineManager.getBestPath(this.stationList[i].name, this.stationList[j].name, lineNameList))
      }
    }
  },
  initData(stationData) {
    this.__init()
    this.__fillData(stationData)
    this.__initPathMatrix()
  },
  
  searchPath(fromStationName, toStationName) {
    if (!this.stationIndexMap.has(fromStationName) || !this.stationIndexMap.has(toStationName)) {
      return []
    }
    if(fromStationName == toStationName) {
      return []
    }
    
    const fromIndex = this.stationIndexMap.get(fromStationName)
    const toIndex = this.stationIndexMap.get(toStationName)
    
    const disPathList = []
    
    // 标记一个站点是否已计算过
    const visited = []
    
    for (let index = 0; index < this.stationCount; index ++) {
      disPathList.push({ distance: this.pathMatrix[fromIndex][index].distance, pathList: [this.pathMatrix[fromIndex][index]] })
      visited.push(false)
    }
    
    for (let i = 0; i < this.stationCount; i ++) {
      let indexOfMin = 0
      let minPathObj = { distance: 9999, pathList: [new Path()]}
      
      for (let j = 0; j < this.stationCount; j ++) {
        if (!visited[j] && disPathList[j].distance < minPathObj.distance) {
          minPathObj = { distance: disPathList[j].distance, pathList: disPathList[j].pathList }
          indexOfMin = j
        }
      }
      
      visited[indexOfMin] = true
      
      // 换乘附加，代表换乘一站相当于多乘坐5站，
      // 用来优先选择换乘少的路线，根据需要修改具体数值
      const transferCost = 5
      
      for (let k = 0; k < this.stationCount; k ++) {
        if (this.pathMatrix[indexOfMin][k].distance < 9999) {
          const distance = disPathList[indexOfMin].distance + this.pathMatrix[indexOfMin][k].distance + transferCost
          if (!visited[k] && (disPathList[k].distance > distance)) {
            const pathList = [...disPathList[indexOfMin].pathList]
            pathList.push(this.pathMatrix[indexOfMin][k])
            disPathList[k] = { distance, pathList }
          }
        }
      }
      
    }
    
    const pathList = disPathList[toIndex].pathList
    const finalPathList = pathList.map(path => {
      path.stationList = this.lineManager.getPathStationNameList(path.lineName, path.fromStationName, path.toStationName)
      return path
    })
    
    return finalPathList
    
  }
}

export default Dijkstra